package com.mygdx.game;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.ScreenAdapter;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.*;
import com.badlogic.gdx.utils.viewport.StretchViewport;
import sun.applet.Main;

/**
 * 主游戏场景（游戏主界面）, 实现 Screen 接口 或者 继承 ScreenAdapter 类
 * 这里就展示一张图片代表游戏主界面
 */
public class GameScreen extends ScreenAdapter {

    //位图文字
    private final BitmapFont bitmapFont;

    //舞台演员
    private Texture mainTexture;
    private Stage stage;
    private MyActor myActor;

    //动画
    private Batch batch;
    private Texture walkTexture;
    private Animation walkAnimation; //行走的动画
    private TextureRegion curFrame;  //当前帧
    private float stateTime; // 状态时间, 渲染时间步 delta 的累加值

    //纹理图集
    private TextureAtlas textureAtlas;

    // 每个小图在在纹理图集中对应的名称常量（实际上就是小图的原文件名，定义在 myatlas.atlas 文件中）
    private static final String MAN= "man";   //人
    private static final String MUSHROOM = "mashroom"; //蘑菇
    private static final String FLOWER = "flower";  //花
    private static final String BUTTON = "button";  //按钮

    // 小图对应的 纹理区域 或 精灵
    private TextureRegion manRegion; //人
    private Sprite mushroomSprite;  //蘑菇精灵
    private Sprite flowerSprite; //鲜花
    private TextureRegion button1Region; //按钮1
    private TextureRegion button2Region; //按钮2


    public GameScreen() {
        //创建游戏人物纹理
        mainTexture = new Texture("badlogic.jpg");

        stage = new Stage(new StretchViewport(MainGame.WORLD_WIDTH, MainGame.WORLD_HEIGHT));
        myActor = new MyActor(new TextureRegion(mainTexture));
        myActor.setPosition(0,stage.getHeight()-myActor.getHeight());
        stage.addActor(myActor);

        batch = new SpriteBatch();
        //动画
        walkTexture = new Texture(Gdx.files.internal("animation_sheet.png"));

        int frameRows = 5; //五行
        int frameCols = 6; //六列

        int perCellWidth = walkTexture.getWidth() / frameCols; //小单元格宽度
        int perCellHeight = walkTexture.getHeight() / frameRows; //小单元格高度

        // 按照指定的宽高作为一个单元格分割大图纹理, 分割后的结果为一个 5 * 6 的纹理区域二维数组, 数组中的元素是分割出来的小人单元格
        TextureRegion[][] regions = TextureRegion.split(walkTexture, perCellWidth, perCellHeight);
        // 把二维数组变为一维数组, 因为 Animation 只能接收一维数组作为关键帧序列, 数组中的一个元素（小人单元格的纹理区域）表示一个关键帧
        TextureRegion[] walkRegions = new TextureRegion[frameRows*frameCols];
        int index = 0;
        for (int row = 0; row < frameRows; row++) {
            for (int col = 0; col < frameCols; col++) {
                walkRegions[index++] = regions[row][col];
            }
        }
        // 使用关键帧（纹理区域）数组 walkFrames 创建一个动画实例, 每一帧（一个小人单元格/纹理区域）播放 0.05 秒
        walkAnimation = new Animation<TextureRegion>(0.05f,walkRegions);

         /*
         * 设置播放模式:
         *
         * Animation.PlayMode.NORMAL: 正常播放一次（默认）
         * Animation.PlayMode.REVERSED: 倒序播放一次
         *
         * Animation.PlayMode.LOOP: 正常循环播放
         * Animation.PlayMode.LOOP_REVERSED: 倒序循环播放
         *
         * Animation.PlayMode.LOOP_RANDOM: 随机循环播放
         * Animation.PlayMode.LOOP_PINGPONG: 开关式（先正序再倒序）循环播放
         */
        walkAnimation.setPlayMode(Animation.PlayMode.LOOP);

        //位图文字

        bitmapFont = new BitmapFont(Gdx.files.internal("bitmapFont.fnt"));




        //纹理图集
        textureAtlas = new TextureAtlas(Gdx.files.internal("myatlas/aaaa.atlas"));
        //根据名称从纹理图集中获得纹理区域
        manRegion = textureAtlas.findRegion(MAN);
        // 也可以根据名称直接由纹理图集创建精灵
        mushroomSprite = textureAtlas.createSprite(MUSHROOM);
        flowerSprite = textureAtlas.createSprite(FLOWER);
        /*
         * 根据 名称 和 索引 从纹理图集中获取纹理区域
         *
         * 特别说明:
         *     纹理图集中的小图名称一般就是小图的原文件名, 但可以给小图加上一个索引（index）属性, 就是在文件名后
         * 面加上下划线和表示索引的数字（name_index.png）, 例如 button_1.png 和 button_2.png 这两个小图文件,
         * gdx-tools 在合成纹理图集时会使用相同的名称（button）分别加上对应的索引值（1 和 2）表示。这样有助于对
         * 业务相同的图片进行统一命名。纹理图集对小图的描述定义在 myatlas.atlas 文件中, 这是一个文本文件, 可以用
         * 记事本打开查看。
         *
         * 因此下面获取按钮的纹理区域时使用 "button" 作为名称并加上对应的索引值来获取。
         */
        button1Region = textureAtlas.findRegion(BUTTON,1);
        button2Region = textureAtlas.findRegion(BUTTON,2);

          /* 给精灵设置位置属性 */
        flowerSprite.setPosition(0,90);
        mushroomSprite.setPosition(0,0);



         /*
         * 动作演示
         *
         * 有些时候动作需要频繁使用, 如果每次要使用动作都重新创建一个对象, 会消耗性能。
         * LibGDX 中对动作实例使用了对象池进行了缓存, 使用完一个动作对象后不会直接让系统回收对象,
         * 而是放到对象池中缓存待下次重复使用。LibGDX 中所有动作实例的获取均通过 Actions 工具类
         * 中的静态方法获取（Actions 中实现了对象池缓存）。
         *
         * 获取到一个动作对象后附加在演员身上执行（addAction）, 动作执行完后会自动从演员身上移除
         * 并放回对象池中缓存。 当然在动作还没有执行完时也可在中途手动移除（removeAction）。
         *
         * 下面对每一种动作的演示放在单独方法中, 按顺序打开相应测试方法的注释进行测试（打开一个方法的
         * 注释后必须要注释掉其他测试方法, 否则多个测试同时执行看不出效果）。
         */

        // 1. 移动动作
        // testMoveToAction();

        // 2. 移动动作（相对）
        //testMoveByAction();

        // 3. 旋转动作
        // testRotateToAction();

        // 4. 旋转动作（相对）
//         testRotateByAction();

        // 5. 缩放动作
//         testScaleToAction();

        // 6. 缩放动作（相对）
//         testScaleByAction();

        // 7. 尺寸改变动作
//         testSizeToAction();

        // 8. 尺寸改变动作（相对）
//         testSizeByAction();

        // 9. 透明度动作
//        testAlphaAction();

        // 10. 并行动作
//         testParallelAction();

        // 11. 顺序动作（包含了延时动作的演示）
//         testSequenceAction();

        // 12. 重复动作
//         testRepeatAction();

        // 13. Runnable 动作
//         testRunnableAction();

        // 14. After 动作
//         testAfterAction();

    }
    /**
     * 14. After 动作: 可用于监听演员动作的执行完成
     */
    private void testAfterAction() {
        myActor.setOrigin(myActor.getWidth()/2,myActor.getHeight()/2);

        MoveToAction moveToAction = Actions.moveTo(150, 300, 3f);
        RotateByAction rotateByAction = Actions.rotateBy(360, 2f);
        RunnableAction run = Actions.run(new Runnable() {
            @Override
            public void run() {
                Gdx.app.log("tag", "执行自己的动作了！");
            }
        });
        // After 动作, 包含一个 runnable 动作
        AfterAction after = Actions.after(run);
        myActor.addAction(moveToAction);
        myActor.addAction(rotateByAction);
        myActor.addAction(after);
    }

    /**
     * 13. Runnable 动作: 适当时机执行自己的代码, 与顺序动作一起使用可用于监听某个动作的完成
     */
    private void testRunnableAction() {
        MoveToAction moveToAction = Actions.moveTo(150, 300, 2f);
        RunnableAction run = Actions.run(new Runnable() {
            @Override
            public void run() {
                Gdx.app.error("tag", "执行runnable了");
            }
        });
        SequenceAction sequence = Actions.sequence(moveToAction, run);
        myActor.addAction(sequence);
    }

    /**
     * 12. 重复动作: 重复 缩小, 放大
     */
    private void testRepeatAction() {
        myActor.setPosition(myActor.getStage().getWidth()/2-myActor.getWidth()/2,myActor.getStage().getHeight()/2-myActor.getHeight()/2);
        myActor.setScale(1f,1f);

        myActor.setOrigin(myActor.getWidth()/2,myActor.getHeight()/2);

        //顺序动作
        SequenceAction sequence = Actions.sequence(Actions.scaleTo(0.5f, 0.5f, 2f), Actions.scaleTo(1f, 1f, 2f));
        RepeatAction forever = Actions.forever(sequence);
//        RepeatAction repeat = Actions.repeat(-1, sequence);  //count=-1 相当于无限循环

        myActor.addAction(forever);
    }

    /**
     * 11. 顺序动作（包含了延时动作的演示）: 先延时, 然后移动, 再旋转并缩放
     */
    private void testSequenceAction() {
        myActor.setPosition(0,0);
        myActor.setScale(1f,1f);
        myActor.setRotation(0);

        myActor.setOrigin(myActor.getWidth()/2,myActor.getHeight()/2);

        // 1. 延时动作, 延时 3 秒
        DelayAction delay = Actions.delay(3f);
        // 2. 移动动作
        MoveToAction moveToAction = Actions.moveTo(150, 300, 2f);
        // 3. 并行动作, 包含 缩放 和 旋转 两个动作
        ParallelAction parallel = Actions.parallel(Actions.moveTo(0, 200, 2f), Actions.scaleTo(0.7f, 0.7f, 2f), Actions.rotateTo(360, 5f));
        // 顺序动作, 包含 delay, moveTo, parallel
        SequenceAction sequence = Actions.sequence(delay, moveToAction, parallel);
        myActor.addAction(sequence);
    }

    /**
     * 10. 并行动作: 同时 移动, 缩放, 旋转
     */
    private void testParallelAction() {
        myActor.setPosition(0,0);
        myActor.setScale(1f,1f);
        myActor.setRotation(0);

        myActor.setOrigin(myActor.getWidth()/2,myActor.getHeight()/2);

        MoveToAction moveToAction = Actions.moveTo(100, 200, 3f);
        ScaleToAction scaleToAction = Actions.scaleTo(0.5f, 0.8f,3f);
        RotateToAction rotateToAction = Actions.rotateTo(360,3f);
        // 并行动作, 包含 moveTo, scaleTo, rotateBy
        ParallelAction parallel = Actions.parallel(moveToAction, scaleToAction, rotateToAction);

        myActor.addAction(parallel);

    }

    /**
     * 9. 透明度动作
     */
    private void testAlphaAction() {
        myActor.getColor().a = 1f; //初始化透明度为1
// 获取一个 Alpha 动作, 5 秒内 alpha 变为 0（完全透明）
        AlphaAction alpha = Actions.alpha(0.5f, 3f);
        myActor.addAction(alpha);
    }

    /**
     * 8. 尺寸改变动作（相对）
     */
    private void testSizeByAction() {
        myActor.setPosition(0, 0);
        // 获取一个 SizeTo 动作, 2 秒内宽高从原来基础上分别增加150, 300
        // 最终宽度为: 256 + 100 = 356
        // 最终高度为: 256 + 100 = 356
        SizeByAction sizeByAction = Actions.sizeBy(100, 100, 2f);
        myActor.addAction(sizeByAction);
    }

    /**
     * 7. 尺寸改变动作
     */
    private void testSizeToAction() {
        myActor.setPosition(0, 0);
        // 获取一个 SizeTo 动作, 2 秒内从原来尺寸变到宽为 150, 高为 300 （最终宽高为 150 * 300）
        SizeToAction sizeToAction = Actions.sizeTo(150, 300, 2f);
        myActor.addAction(sizeToAction);
    }

    /**
     * 6. 缩放动作（相对）
     */
    private void testScaleByAction() {
        myActor.setPosition(myActor.getStage().getWidth() / 2 - myActor.getWidth() / 2, myActor.getStage().getHeight() / 2 - myActor.getHeight() / 2);
        myActor.setOrigin(myActor.getWidth() / 2, myActor.getHeight() / 2);

        myActor.setScale(0.8f, 0.8f);
        // 获取一个 ScaleBy 动作, 2 秒内水平和竖直方向缩放比从 原缩放比基础上 分别加上 0.5 和 0.5（正数表示增加, 负数表示减少）,
        // ScaleBy 是对原缩放值单纯的数值相加, 最终水平和竖直方向的缩放比均为: 0.8 + 0.5 = 1.3
        ScaleByAction scaleByAction = Actions.scaleBy(0.5f, 0.5f, 2f);
        myActor.addAction(scaleByAction);
    }

    /**
     * 5. 缩放动作
     */
    private void testScaleToAction() {
        myActor.setPosition(myActor.getStage().getWidth() / 2 - myActor.getWidth() / 2, myActor.getStage().getHeight() / 2 - myActor.getHeight() / 2);
        myActor.setOrigin(myActor.getWidth() / 2, myActor.getHeight() / 2);

        myActor.setScale(0.8f, 0.8f);

        // 获取一个 ScaleTo 动作, 2 秒内水平和竖直方向缩放比从 原缩放比 分别缩放到 0.5 和 0.5,
        // 最终水平和竖直方向缩放比分别为 0.5 和 0.5
        ScaleToAction scaleToAction = Actions.scaleTo(0.5f, 0.5f, 2f);
        myActor.addAction(scaleToAction);
    }

    /**
     * 4. 旋转动作（相对）
     */
    private void testRotateByAction() {
        myActor.setPosition(myActor.getStage().getWidth() / 2 - myActor.getWidth() / 2, myActor.getStage().getHeight() / 2 - myActor.getHeight() / 2);
        myActor.setOrigin(myActor.getWidth() / 2, myActor.getHeight() / 2);

        myActor.setRotation(-90);
        // 获取一个 RotateBy 动作, 2 秒内 从原角度基础上增加90度（最终角度为 -90 + -90 = -180 度）
        RotateByAction rotateByAction = Actions.rotateBy(-90, 2f);
        myActor.addAction(rotateByAction);
    }

    /**
     * 3. 旋转动作
     */
    private void testRotateToAction() {
        //初始化演员位置为舞台中间
        myActor.setPosition(myActor.getStage().getWidth() / 2 - myActor.getWidth() / 2, myActor.getStage().getHeight() / 2 - myActor.getHeight() / 2);
        // 缩放和旋转支点设置到演员中心
        myActor.setOrigin(myActor.getWidth() / 2, myActor.getHeight() / 2);
        // 设置演员的初始角度为 -90 度（逆时针为正, 顺时针为负）
        myActor.setRotation(-90);
        // 获取一个 RotateTo 动作, 2 秒内 从原角度 旋转到 -270 度（最终角度为 -270 度）
        RotateToAction rotateToAction = Actions.rotateTo(-270, 2.0f);
        myActor.addAction(rotateToAction);
    }

    /**
     * 2. 移动动作（相对）
     */
    private void testMoveByAction() {
        //初始化演员位置为舞台中间
        myActor.setPosition(myActor.getStage().getWidth() / 2 - myActor.getWidth() / 2, myActor.getStage().getHeight() / 2 - myActor.getHeight() / 2);
        //  2 秒内, 在演员在原位置基础上, 水平方向移动 0, 竖直方向移动 -200
        MoveByAction moveByAction = Actions.moveBy(0, -200, 2.0f);
        myActor.addAction(moveByAction);
    }

    //移动动作
    private void testMoveToAction() {
        //设置初始演员位置
        myActor.setPosition(0, 100);
        // 获取一个 MoveTo 动作, 3 秒内移动到 (150, 300) 的位置
        MoveToAction moveToAction = Actions.moveTo(150, 300, 3.0f);
        myActor.addAction(moveToAction);
        /*
         * 动作执行原理（查看 Actor 和相应 Action 的源码）:
         *
         * 实际上动作添加到演员身上的后, 动作被存放到一个数组中, 然后在更新演员逻辑的 actor.act()方法中遍历存放动作的数组,
         * 对每一个动作根据时间步 delta 改变演员相应的状态属性值。然后在绘制演员的 actor.draw() 方法中绘制演员时使用新的
         * 状态属性值绘制, 和上一帧相比, 就显的演员被“动”起来了。
         */
    }

    @Override
    public void render(float delta) {
        super.render(delta);
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        // 累加时间步（stateTime 也可表示游戏的运行时间）
        stateTime+=Gdx.graphics.getDeltaTime();
        Gdx.app.error("tag","stateTime = "+stateTime);
        // 根据当前 播放模式 获取当前关键帧, 就是在 stateTime 这个时刻应该播放哪一帧
        curFrame = (TextureRegion) walkAnimation.getKeyFrame(stateTime);

        batch.begin();
        // 绘制当前关键帧
        batch.draw(curFrame,50,100);
        bitmapFont.draw(batch,"跨平台框架。\n hello world游戏 \nfff啊哈哈哈哈oijsdf",100,100);

        //绘制精灵
        flowerSprite.draw(batch);   //花
        mushroomSprite.draw(batch);  //蘑菇
        //绘制纹理区域
        batch.draw(manRegion,30,70);  //人
        batch.draw(button1Region,100,70);  //按钮1
        batch.draw(button2Region,180,70);  //按钮2

        batch.end();

        stage.act();
        stage.draw();
    }

    @Override
    public void dispose() {
        super.dispose();
        if (stage != null) {
            stage.dispose();
        }
        if (mainTexture != null) {
            mainTexture.dispose();
        }
        if (walkTexture!=null)
        {
            walkTexture.dispose();
        }
        if (batch!=null)
        {
            batch.dispose();
        }
    }
}
